<?php
class Mac_Controller_Front
{
    /**
     * HTTP Request
     * @var Controller_HTTPRequest 
     */
    private $request;
    
    private $defaultControllerMCA = array();
    
    private $errorControllerMCA = array();
    
	private static $instance = null;

	public static function getInstance ()
	{
		if (self::$instance === null) {
			self::$instance = new self();
		}

		return self::$instance;
	}
    
    private function __construct () {}
	
	public function dispatch (Mac_Controller_HTTPRequest $request)
	{
        $this->request = $request;
        
        $controllerName = $this->getControllerClassName();
        if(!class_exists($controllerName)){
            die($controllerName.' la classe n\'existe pas TODO launch a 404'); // TODO : 404
        }
        try {
            $this->checkOrderedParams();
            $controller = new $controllerName($this->request);
            $controller->initView(
                $this->getModuleName(),
                $this->breakCamelCase($this->getControllerName()),
                $this->breakCamelCase($this->getActionName())
            );
            call_user_func_array(
                array(
                    $controller,
                    $this->getActionMethodName()
                ),
                $this->request->getOrderedParams()
            );
            
            $response = new Mac_Controller_HTTPResponse();
            $response->setBody($controller->getLayout()->content());
            $response->send();
        } catch (Controller_Exception_Action_NotEnoughParameters $e) {
            $response = new Mac_Controller_HTTPResponse();
            $response->setHttpResponseCode(404);
            $response->setBody('Putain d\'erreur : pas assez de paramètres fournis au controller');
            $response->send();
        }
	}
	
	public function dispatchError ($error)
	{
	    $request = clone $this->request;
	    $request->setModuleName($this->errorControllerMCA['module']);
	    $request->setControllerName($this->errorControllerMCA['controller']);
	    $request->setActionName($this->errorControllerMCA['action']);
	    $request->setParams(array('error' => $error));
	    
	    $this->dispatch($request);
	}
	
	public function setDefaultControllerMCA ($module, $controller, $action = 'index')
	{
	    $this->defaultControllerMCA['module'] = $module;
	    $this->defaultControllerMCA['controller'] = $controller;
	    $this->defaultControllerMCA['action'] = $action;
	}
	
    public function setErrorControllerMCA ($module, $controller, $action = 'index')
    {
        $this->errorControllerMCA['module'] = $module;
        $this->errorControllerMCA['controller'] = $controller;
        $this->errorControllerMCA['action'] = $action;
    }
    
    private function checkOrderedParams ()
    {
        $nbSentParams = count($this->request->getOrderedParams());
		
		$controller = $this->getControllerClassName();
		$action = $this->getActionMethodName();
		$actionCalled = new ReflectionMethod($controller, $action);
		$nbExpectedParameters = (int)$actionCalled->getNumberOfRequiredParameters();
        
		if ($nbSentParams < $nbExpectedParameters) {
			throw new Mac_Controller_Exception_Action_NotEnoughParameters('Not enough parameters for call '.$action.' in '.$controller.'. Expecting '.$nbExpectedParameters.', '.$nbSentParams.' given');
		}
    }
    
    private function breakCamelCase ($actionName)
    {
        $matches = array();
        $upperscored = preg_match_all('#[A-Z][a-z0-9]+#', ucfirst($actionName), $matches);
        return strtolower(implode('-', $matches[0]));
    }
    
    private function getModuleName ()
    {
        return ($this->request->getModuleName() === '') ? $this->defaultControllerMCA['module'] : $this->request->getModuleName();
    }
    
    private function getControllerName ()
    {
        return ($this->request->getControllerName() === '') ? $this->defaultControllerMCA['controller'] : $this->request->getControllerName();
    }
    
    private function getActionName ()
    {
        return ($this->request->getActionName() === '') ? $this->defaultControllerMCA['action'] : $this->request->getActionName();
    }
    
    private function getModulePrefixClassName ()
    {
        if($this->request->getModuleName() !== '') {
            return ucfirst($this->request->getModuleName()).'_';
        } else {
            return '';
        }
    }
    
    private function getControllerClassName ()
    {
        return $this->getModulePrefixClassName().$this->getControllerName().'Controller';
    }
    
    private function getActionMethodName ()
    {
        return $this->getActionName().'Action';
    }
}
